#include <iostream>
#include "stdio.h"
#include "stdlib.h"

class Cls
{
public:
    Cls(int i = 0):i_(i){}

    ~Cls()
    {
        std::cout << counter++ << " call ~Cls()" << std::endl; 
    }
private:
    int i_;
    static int counter;
};
int Cls::counter = 1;


// void* operator new[](size_t sz)
// {
//     printf("数组实际长度: %ld\n", sz);
//     void* p = malloc(sz);
//     return p;
// }

// void operator delete[](void* fp)
// {
//     printf("实际释放的地址: %p\n", fp);
//     free(fp);
// }

const long long len = 10;

void test1()
{
    Cls* array = new Cls[len];
    char* ptr = (char*)array;
    printf("数组预期长度: %d\n", len*sizeof(Cls));
    printf("数组首地址: %p\n", ptr);
    delete[] array;
}



void test2()
{
    //开辟一个int对象，值为默认(0)
    int* pa1 = new int;

    //开辟一个int对象，指定值为1
    int* pa2 = new int(1);

    //开辟int数组
    int* parr1 = new int[10];
    int* parr2 = new int[5]{1,2,3,4,5};//since c++11
    int* parr3 = new int[5]{1,2,3};////since c++11, 后两个数是默认值0

    int* parr4 = new int[0];//可以, 但解引用行为是未定义的
    /*If this argument is zero, the function still returns a distinct non-null pointer 
    on success (although dereferencing this pointer leads to undefined behavior).*/

    //释放空间
    delete pa1;
    delete pa2;

    delete[] parr1;
    delete[] parr2;
    delete[] parr3;
    delete[] parr4;
}

class People
{
public:
    People() : age_(0), name_("unkown")
    {
        std::cout << "default constructor" << std::endl;
    }

    People(int age, const std::string& name) : age_(age), name_(name)
    {
        std::cout << "call the constructor of People" << std::endl;
    }
    ~People()
    {
        std::cout << "call the destructor of People" << std::endl;
    }

private:
    int age_;
    std::string name_;
};

void test3()
{
    People* p1 = new People;//调用默认构造函数
    People* p2 = new People(18, "Jcole");//传参调用构造函数
    People* p3 = new People[3];
    People* p4 = new People[3]{{10,"Bill"}, {20, "Tyler"}, {30, "Lamar"}};

    delete p1;
    delete p2;
    delete[] p3;
    delete[] p4;
}


void test4()
{
    // // 对于内置类型
    // int* p1 = new int[10];
    // delete p1;
    // // 不会出错，因为delete内置类型对象时，只需回收空间，不用调用析构函数

    // // 对于自定义类型
    // Cls* p2 = new Cls[10];
    // delete p2;
    // // 出错，delete p2只会调用一次析构函数，其它对象都没有析构，释放空间后可能会导致内存泄漏

    //未定义
    int* p3 = new int;
    delete[] p3;

    //可能在非法空间调用了析构函数
    Cls* p4 = new Cls;
    delete[] p4;
}

int main()
{
    //test1();
    // test2();
    // test3();
    test4();
    return 0;
}